2020-06-25 23:55:22
Author: Cedric Huchuan Xia (email, github)
Affiliation: Penn Lifespan Informatics and Neuroimaging Center (PennLINC)
1. Setup Environment
require(reshape2)
require(sna)
require(tidyr)
project_path = "~/Documents/xia_gps/"
data_path = file.path(project_path,"data/flywheel_data/network_txt")
2. Setup Target and Database FC
atlases = c("HarvardOxford","desikanKilliany","aal116","schaefer200x7","power264","gordon333","glasser360","schaefer400x7")
subj_net_files_1 = list()
subj_net_files_2 = list()
for (atlas in atlases) {
subjects = list.files(file.path(data_path))
for (subj in subjects) {
subj_files = list.files(file.path(data_path,subj))
net_pattern_1 = paste0("*task-rest*single*",atlas,"*")
net_pattern_2 = paste0("*task-rest*multi*",atlas,"*")
file_path_1 = file.path(data_path,
subj,subj_files[grep(glob2rx(net_pattern_1),subj_files)])
file_path_2 = file.path(data_path,
subj,subj_files[grep(glob2rx(net_pattern_2),subj_files)])
if (length(file_path_1)>0) {subj_net_files_1[[atlas]][[subj]] = read.table(file_path_1) }
if (length(file_path_2)>0) {subj_net_files_2[[atlas]][[subj]] = read.table(file_path_2) }
}
}
Visutalize FC matrix
matrix_fc = matrix(NA, 264,264)
matrix_fc[lower.tri(matrix_fc, diag = F)] = subj_net_files_1$power264[[1]][,1]
matrix_fc = symmetrize(matrix_fc, rule = "lower")
levelplot(matrix_fc,scales=list(draw=FALSE),col.regions = rev(rainbow(80))[-c(1:5)], region =T, ylab.right = "Pearson correlation", main=list(label='Singleband FC'),xlab="",ylab="")

4. Create Subj Similarity Matrix
gps_wide_matrix = data.frame()
for (subj in arrange(subj_days,`Days Collected`)$IID){
#if ((subj %in% subj_days$IID[which(subj_days$`Days Collected`<=10)]) == T) {
for (part in 1:1){
half_1 = gps_clean2_feature$subj_mat_1[[subj]][[part]]$cor
half_2 = gps_clean2_feature$subj_mat_2[[subj]][[part]]$cor
half_1_half_2 = c(half_1,half_2)
gps_wide_matrix = rbind(gps_wide_matrix,half_1)
gps_wide_matrix = rbind(gps_wide_matrix,half_2)
}
#}
}
gps_wide_matrix = t(gps_wide_matrix)
gps_corplot = rquery.cormat(gps_wide_matrix, type = "full",graph=FALSE)
gps_corplot$subj = arrange(subj_days,`Days Collected`)$IID
levelplot(gps_corplot$r,scales=list(draw=FALSE),col.regions = rev(rainbow(1000))[-c(1:20)], region =T, ylab.right = "Pearson correlation", main=list(label='GPS Feature Similarity'),xlab="",ylab="")


fc_corplot$schaefer400x7$plot

fc_corplot$schaefer200x7$plot

fc_corplot$power264$plot

5. Create FC Atlas Similarity Matrix
fc_cor_r = lapply(fc_corplot, function(atlas) atlas$sim_mat$r[lower.tri(atlas$sim_mat$r)])
fc_cor_r_cor = lapply(fc_cor_r, function(r1) sapply(fc_cor_r, function(r2) cor.test(r1,r2)))
fc_cor_r_cor_mat = sapply(fc_cor_r_cor, function(atlas) atlas['estimate',])
levelplot(fc_cor_r_cor_mat,col.regions = rev(rainbow(100))[-c(1:20)],
region =T, ylab.right = "Pearson correlation",
main=list(label=paste('FC Atlas Similarity Matrix')), xlab="",ylab="",
scales=list(x=list(at = 1:length(atlases), labels=atlases,rot=90, tck = 0),
y=list(at = 1:length(atlases),labels=atlases, tck = 0)))

6. Compute Whole Brain FC-GPS Similarity Matrix Correlations
wbFC_gps_cor = unlist(sapply(fc_cor_r, function(atlas) cor.test(atlas, gps_corplot$r[lower.tri(gps_corplot$r)]))[c('estimate'),])
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
7: In readChar(file, size, TRUE) : truncating string with embedded nuls
8: In readChar(file, size, TRUE) : truncating string with embedded nuls
9: In readChar(file, size, TRUE) : truncating string with embedded nuls
wbFC_gps_cor_df = data_frame(atlas = gsub("\\..*","",names(wbFC_gps_cor)), corr = wbFC_gps_cor)
p = ggplot(data=wbFC_gps_cor_df, aes(x=atlas, y=corr)) +
geom_bar(stat="identity") + scale_y_continuous(limits=c(-0.5,0.5)) +
theme_cowplot() + theme(axis.text.x = element_text(angle = 45, vjust = 0.5)) +
ylab("FC-GPS Similarity Matrices Correlatons") + xlab("")
p

7. Match FC target to database

8. Permutation Test for Matching
subj_net_perm_1 = get_subj_net_perm(subj_net_files_1)
Error in sample(length(subj_net_files[[atalas]])) :
object 'atalas' not found
data_long <- gather(perm_acc, key = "atlas", value = "accuracy", atlases)
Note: Using an external vector in selections is ambiguous.
[34mℹ[39m Use `all_of(atlases)` instead of `atlases` to silence this message.
[34mℹ[39m See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
[90mThis message is displayed once per session.[39m

get_com_fc_accuracy = function(atlas_now){
com_nums = read.table(file.path(atlas_path,atlas_now,paste0(atlas_now,"CommunityAffiliation.1D")))$V1
com_names = read.table(file.path(atlas_path,atlas_now,paste0(atlas_now,"CommunityNames.txt")))$V1
com_names = substr(com_names,0,3)
if (atlas_now == "power264") {com_names[c(1,2)] = c("smH","smM")}
fc_com_1 = get_fc_com(com_nums, com_names, atlas_now, subj_net_files_1)
fc_com_2 = get_fc_com(com_nums, com_names, atlas_now, subj_net_files_2)
#fc_com_1_sig = fc_com_1[names(which(fc_schaef400_7_com_gps$fc_gps_df$sig == T))]
#fc_com_2_sig = fc_com_2[names(which(fc_schaef400_7_com_gps$fc_gps_df$sig == T))]
single_multi_acc_com = get_acc_finger(fc_com_1,fc_com_2)
single_multi_acc_com_df = data.frame(atlas = names(single_multi_acc_com$acc), accuracy = single_multi_acc_com$acc, FC_GPS_sig = fc_schaef400_7_com_gps$fc_gps_df$sig == T)
p = ggplot(data=single_multi_acc_com_df, aes(x=reorder(atlas, accuracy), y=accuracy, fill = FC_GPS_sig)) +
geom_bar(stat="identity") +
theme_cowplot() + theme(axis.text.x = element_text(angle = 90, vjust = 0.5)) +
ylab("FC Fingerprint Accuracy") + xlab("")
return(list(df = single_multi_acc_com_df, plot = p))
}
s400_fc_com_acc$plot / s200_fc_com_acc$plot

atlas_now
[1] "schaefer400x7"
LS0tCnRpdGxlOiAiRnVuY3Rpb25hbCBDb25uZWN0aXZpdHkgRmluZ2VycHJpbnRpbmciCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgaW5jbHVkZXM6CiAgICAgIGFmdGVyX2JvZHk6IGZvb3Rlci5odG1sCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICB0b2NfY29sbGFwc2VkOiB5ZXMKLS0tCmByIFN5cy50aW1lKClgCgpBdXRob3I6IFtDZWRyaWMgSHVjaHVhbiBYaWFdKGh0dHBzOi8vd3d3LnBlbm5saW5jLmlvL3RlYW0vQ2VkcmljLUh1Y2h1YW4tWGlhKSAoW2VtYWlsXShoeGlhQHVwZW5uLmVkdSksIFtnaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9jZWRyaWN4LykpCgpBZmZpbGlhdGlvbjogUGVubiBMaWZlc3BhbiBJbmZvcm1hdGljcyBhbmQgTmV1cm9pbWFnaW5nIENlbnRlciAoW1Blbm5MSU5DXShwZW5ubGluYy5pbykpIAoKKioqCgojIyMgMS4gU2V0dXAgRW52aXJvbm1lbnQgCmBgYHtyIGxvYWQgbGlicmFyaWVzLCBtZXNzYWdlPUZBTFNFfQpyZXF1aXJlKHJlc2hhcGUyKQpyZXF1aXJlKHNuYSkKcmVxdWlyZSh0aWR5cikKYGBgCgpgYGB7ciBkZWZpbmUgcGF0aHN9CnByb2plY3RfcGF0aCA9ICJ+L0RvY3VtZW50cy94aWFfZ3BzLyIKZGF0YV9wYXRoID0gZmlsZS5wYXRoKHByb2plY3RfcGF0aCwiZGF0YS9mbHl3aGVlbF9kYXRhL25ldHdvcmtfdHh0IikKCmBgYAoKIyMjIDIuIFNldHVwIFRhcmdldCBhbmQgRGF0YWJhc2UgRkMKYGBge3J9CgphdGxhc2VzID0gYygiSGFydmFyZE94Zm9yZCIsImRlc2lrYW5LaWxsaWFueSIsImFhbDExNiIsInNjaGFlZmVyMjAweDciLCJwb3dlcjI2NCIsImdvcmRvbjMzMyIsImdsYXNzZXIzNjAiLCJzY2hhZWZlcjQwMHg3IikKc3Vial9uZXRfZmlsZXNfMSA9IGxpc3QoKQpzdWJqX25ldF9maWxlc18yID0gbGlzdCgpCgpmb3IgKGF0bGFzIGluIGF0bGFzZXMpIHsKICBzdWJqZWN0cyA9IGxpc3QuZmlsZXMoZmlsZS5wYXRoKGRhdGFfcGF0aCkpCiAgZm9yIChzdWJqIGluIHN1YmplY3RzKSB7CiAgICBzdWJqX2ZpbGVzID0gbGlzdC5maWxlcyhmaWxlLnBhdGgoZGF0YV9wYXRoLHN1YmopKQogICAgbmV0X3BhdHRlcm5fMSA9IHBhc3RlMCgiKnRhc2stcmVzdCpzaW5nbGUqIixhdGxhcywiKiIpCiAgICBuZXRfcGF0dGVybl8yID0gcGFzdGUwKCIqdGFzay1yZXN0Km11bHRpKiIsYXRsYXMsIioiKQogICAgCiAgICBmaWxlX3BhdGhfMSA9IGZpbGUucGF0aChkYXRhX3BhdGgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViaixzdWJqX2ZpbGVzW2dyZXAoZ2xvYjJyeChuZXRfcGF0dGVybl8xKSxzdWJqX2ZpbGVzKV0pCiAgICBmaWxlX3BhdGhfMiA9IGZpbGUucGF0aChkYXRhX3BhdGgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViaixzdWJqX2ZpbGVzW2dyZXAoZ2xvYjJyeChuZXRfcGF0dGVybl8yKSxzdWJqX2ZpbGVzKV0pCiAgICAKICAgIGlmIChsZW5ndGgoZmlsZV9wYXRoXzEpPjApIHtzdWJqX25ldF9maWxlc18xW1thdGxhc11dW1tzdWJqXV0gPSByZWFkLnRhYmxlKGZpbGVfcGF0aF8xKSB9CiAgICBpZiAobGVuZ3RoKGZpbGVfcGF0aF8yKT4wKSB7c3Vial9uZXRfZmlsZXNfMltbYXRsYXNdXVtbc3Vial1dID0gcmVhZC50YWJsZShmaWxlX3BhdGhfMikgfQogIH0KfQpgYGAKCgojIyMjIFZpc3V0YWxpemUgRkMgbWF0cml4CmBgYHtyIH0KbWF0cml4X2ZjID0gbWF0cml4KE5BLCAyNjQsMjY0KQptYXRyaXhfZmNbbG93ZXIudHJpKG1hdHJpeF9mYywgZGlhZyA9IEYpXSA9IHN1YmpfbmV0X2ZpbGVzXzEkcG93ZXIyNjRbWzFdXVssMV0KbWF0cml4X2ZjID0gc3ltbWV0cml6ZShtYXRyaXhfZmMsIHJ1bGUgPSAibG93ZXIiKQpsZXZlbHBsb3QobWF0cml4X2ZjLHNjYWxlcz1saXN0KGRyYXc9RkFMU0UpLGNvbC5yZWdpb25zID0gcmV2KHJhaW5ib3coODApKVstYygxOjUpXSwgcmVnaW9uID1ULCB5bGFiLnJpZ2h0ID0gIlBlYXJzb24gY29ycmVsYXRpb24iLCBtYWluPWxpc3QobGFiZWw9J1NpbmdsZWJhbmQgRkMnKSx4bGFiPSIiLHlsYWI9IiIpCmBgYAoKCgoKIyMjIDQuIENyZWF0ZSBTdWJqIFNpbWlsYXJpdHkgTWF0cml4CmBgYHtyIEdQUyBzaW1pbGFyaXR5IG1hdHJpeH0KZ3BzX3dpZGVfbWF0cml4ID0gZGF0YS5mcmFtZSgpCgpmb3IgKHN1YmogaW4gYXJyYW5nZShzdWJqX2RheXMsYERheXMgQ29sbGVjdGVkYCkkSUlEKXsKICAjaWYgKChzdWJqICVpbiUgc3Vial9kYXlzJElJRFt3aGljaChzdWJqX2RheXMkYERheXMgQ29sbGVjdGVkYDw9MTApXSkgPT0gVCkgewogICAgZm9yIChwYXJ0IGluIDE6MSl7CiAgICAgIGhhbGZfMSA9IGdwc19jbGVhbjJfZmVhdHVyZSRzdWJqX21hdF8xW1tzdWJqXV1bW3BhcnRdXSRjb3IKICAgICAgaGFsZl8yID0gZ3BzX2NsZWFuMl9mZWF0dXJlJHN1YmpfbWF0XzJbW3N1YmpdXVtbcGFydF1dJGNvcgogICAgICBoYWxmXzFfaGFsZl8yID0gYyhoYWxmXzEsaGFsZl8yKQogICAgICBncHNfd2lkZV9tYXRyaXggPSByYmluZChncHNfd2lkZV9tYXRyaXgsaGFsZl8xKQogICAgICBncHNfd2lkZV9tYXRyaXggPSByYmluZChncHNfd2lkZV9tYXRyaXgsaGFsZl8yKQogICAgICB9CiAgICAjfQp9CgpncHNfd2lkZV9tYXRyaXggPSB0KGdwc193aWRlX21hdHJpeCkKZ3BzX2NvcnBsb3QgPSBycXVlcnkuY29ybWF0KGdwc193aWRlX21hdHJpeCwgdHlwZSA9ICJmdWxsIixncmFwaD1GQUxTRSkKZ3BzX2NvcnBsb3Qkc3ViaiA9IGFycmFuZ2Uoc3Vial9kYXlzLGBEYXlzIENvbGxlY3RlZGApJElJRAoKbGV2ZWxwbG90KGdwc19jb3JwbG90JHIsc2NhbGVzPWxpc3QoZHJhdz1GQUxTRSksY29sLnJlZ2lvbnMgPSByZXYocmFpbmJvdygxMDAwKSlbLWMoMToyMCldLCByZWdpb24gPVQsIHlsYWIucmlnaHQgPSAiUGVhcnNvbiBjb3JyZWxhdGlvbiIsIG1haW49bGlzdChsYWJlbD0nR1BTIEZlYXR1cmUgU2ltaWxhcml0eScpLHhsYWI9IiIseWxhYj0iIikKYGBgCgpgYGB7ciBGQyBjYWxjdWxhdGUgYmV0d2Vlbi1hdGxhcyBzaW1pbGFyaXR5IG1hdHJpeH0KCnNpbV9wbG90cyA9IGZ1bmN0aW9uKHN1Ympfc2VxLCBpZHMsYXRsYXNlcywgc3Vial9uZXRfZmlsZXNfMSwgc3Vial9uZXRfZmlsZXNfMil7CiAgZmNfd2lkZW1hdHJpeCA9IGxpc3QoKQogIGZjX2NvcnBsb3QgPSBsaXN0KCkKICBmb3IgKGF0bGFzIGluIGF0bGFzZXMpewogICAgcHJpbnQocGFzdGUoImF0bGFzOiIsIGF0bGFzKSkKICAgICAgZm9yIChzdWJqIGluIHN1Ympfc2VxKXsKICAgICAgICAgICNwcmludChzdWJqKQogICAgICAgICAgc3Vial9pZCA9IGFzLmNoYXJhY3RlcihpZHNbaWRzJGJlaXdlSUQgPT0gc3ViaiwnQkJMSUQnXSkKICAgICAgICAgICNwcmludChzdWJqX2lkKQogICAgICAgICAgZmNfMSA9IHVubGlzdChzdWJqX25ldF9maWxlc18xW1thdGxhc11dW1tzdWJqX2lkXV0kVjEpCiAgICAgICAgICBmY18yID0gdW5saXN0KHN1YmpfbmV0X2ZpbGVzXzJbW2F0bGFzXV1bW3N1YmpfaWRdXSRWMSkKICAgICAgICAgIAogICAgICAgICAgZmNfd2lkZW1hdHJpeFtbYXRsYXNdXSA9IGNiaW5kKGZjX3dpZGVtYXRyaXhbW2F0bGFzXV0sZmNfMSkKICAgICAgICAgIGZjX3dpZGVtYXRyaXhbW2F0bGFzXV0gPSBjYmluZChmY193aWRlbWF0cml4W1thdGxhc11dLGZjXzIpCiAgICAgICAgICAjcHJpbnQoZGltKGZjX3dpZGVtYXRyaXhbW2F0bGFzXV0pWzJdKQogICAgICB9CiAgICAgIHByaW50KGRpbShmY193aWRlbWF0cml4W1thdGxhc11dKVsyXSkKICAgICAgZmNfY29ycGxvdFtbYXRsYXNdXSRzaW1fbWF0ID0gcnF1ZXJ5LmNvcm1hdChmY193aWRlbWF0cml4W1thdGxhc11dLCB0eXBlID0gImZ1bGwiLGdyYXBoPUZBTFNFKQogICAgICBmY19jb3JwbG90W1thdGxhc11dJHN1YmogPSBzdWJqX3NlcQogICAgICBmY19jb3JwbG90W1thdGxhc11dJHBsb3QgPSBsZXZlbHBsb3QoZmNfY29ycGxvdFtbYXRsYXNdXSRzaW1fbWF0JHIsc2NhbGVzPWxpc3QoZHJhdz1GQUxTRSksY29sLnJlZ2lvbnMgPSByZXYocmFpbmJvdygxMDApKVstYygxOjIwKV0sIHJlZ2lvbiA9VCwgeWxhYi5yaWdodCA9ICJQZWFyc29uIGNvcnJlbGF0aW9uIiwgbWFpbj1saXN0KGxhYmVsPXBhc3RlKCdGQyBTaW1pbGFyaXR5IE1hdHJpeCBcbiAnLCBhdGxhcykpLHhsYWI9IlN1YmplY3RzIix5bGFiPSJTdWJqZWN0cyIpCiAgfQogIHJldHVybihmY19jb3JwbG90KQp9CgpzdWJqX3NlcSA9IGdwc19jb3JwbG90JHN1YmoKZmNfY29ycGxvdCA9IHNpbV9wbG90cyhzdWJqX3NlcSwgaWRzLCBhdGxhc2VzLCBzdWJqX25ldF9maWxlc18xLCBzdWJqX25ldF9maWxlc18yKQpgYGAKYGBge3J9CmZjX2NvcnBsb3Qkc2NoYWVmZXI0MDB4NyRwbG90CmBgYAoKYGBge3J9CmZjX2NvcnBsb3Qkc2NoYWVmZXIyMDB4NyRwbG90CmBgYAoKYGBge3J9CmZjX2NvcnBsb3QkcG93ZXIyNjQkcGxvdApgYGAKCgojIyMgNS4gQ3JlYXRlIEZDIEF0bGFzIFNpbWlsYXJpdHkgTWF0cml4CgpgYGB7ciBjYWxjdWxhdGUgc2ltaWxpYXJ5IG1hdHJpeCBiZXR3ZWVuIGF0bGFzZXN9CmZjX2Nvcl9yID0gbGFwcGx5KGZjX2NvcnBsb3QsIGZ1bmN0aW9uKGF0bGFzKSBhdGxhcyRzaW1fbWF0JHJbbG93ZXIudHJpKGF0bGFzJHNpbV9tYXQkcildKQpmY19jb3Jfcl9jb3IgPSBsYXBwbHkoZmNfY29yX3IsIGZ1bmN0aW9uKHIxKSBzYXBwbHkoZmNfY29yX3IsIGZ1bmN0aW9uKHIyKSBjb3IudGVzdChyMSxyMikpKQpmY19jb3Jfcl9jb3JfbWF0ID0gc2FwcGx5KGZjX2Nvcl9yX2NvciwgZnVuY3Rpb24oYXRsYXMpIGF0bGFzWydlc3RpbWF0ZScsXSkKCmxldmVscGxvdChmY19jb3Jfcl9jb3JfbWF0LGNvbC5yZWdpb25zID0gcmV2KHJhaW5ib3coMTAwKSlbLWMoMToyMCldLCAKICAgICAgICAgIHJlZ2lvbiA9VCwgeWxhYi5yaWdodCA9ICJQZWFyc29uIGNvcnJlbGF0aW9uIiwgCiAgICAgICAgICBtYWluPWxpc3QobGFiZWw9cGFzdGUoJ0ZDIEF0bGFzIFNpbWlsYXJpdHkgTWF0cml4JykpLCB4bGFiPSIiLHlsYWI9IiIsIAogICAgICAgICAgc2NhbGVzPWxpc3QoeD1saXN0KGF0ID0gMTpsZW5ndGgoYXRsYXNlcyksIGxhYmVscz1hdGxhc2VzLHJvdD05MCwgdGNrID0gMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9bGlzdChhdCA9IDE6bGVuZ3RoKGF0bGFzZXMpLGxhYmVscz1hdGxhc2VzLCB0Y2sgPSAwKSkpCgpgYGAKIyMjIDYuIENvbXB1dGUgV2hvbGUgQnJhaW4gRkMtR1BTIFNpbWlsYXJpdHkgTWF0cml4IENvcnJlbGF0aW9ucwoKYGBge3IgY29tcGFyZSBGQyBhbmQgR1BTIHNpbWlsYXJpdHkgbWF0cml4fQp3YkZDX2dwc19jb3IgPSB1bmxpc3Qoc2FwcGx5KGZjX2Nvcl9yLCBmdW5jdGlvbihhdGxhcykgY29yLnRlc3QoYXRsYXMsIGdwc19jb3JwbG90JHJbbG93ZXIudHJpKGdwc19jb3JwbG90JHIpXSkpW2MoJ2VzdGltYXRlJyksXSkKd2JGQ19ncHNfY29yX2RmID0gZGF0YV9mcmFtZShhdGxhcyA9IGdzdWIoIlxcLi4qIiwiIixuYW1lcyh3YkZDX2dwc19jb3IpKSwgY29yciA9IHdiRkNfZ3BzX2NvcikKcCA9IGdncGxvdChkYXRhPXdiRkNfZ3BzX2Nvcl9kZiwgYWVzKHg9YXRsYXMsIHk9Y29ycikpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cz1jKC0wLjUsMC41KSkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC41KSkgKwogIHlsYWIoIkZDLUdQUyBTaW1pbGFyaXR5IE1hdHJpY2VzIENvcnJlbGF0b25zIikgKyB4bGFiKCIiKQpwCmBgYAoKIyMjIDcuIENvbXB1dGUgQ29tbXVuaXR5LUxldmVsIEZDLUdQUyBTaW1pbGFyaXR5IE1hdHJpeCBDb3JyZWxhdGlvbnMKCgpgYGB7ciBoZWxwZXIgZnVuY3Rpb25zIGZvciBnZXQgc3BlY2lmaWMgcGFydCBvZiBicmFpbn0KdmVjdG9yX3RvX21hdCA9IGZ1bmN0aW9uKGZjX3ZlY3RvciwgbWV0aG9kID0gImhhbGYiKXsKICAKICBpZiAobWV0aG9kID09ICJmdWxsIil7CiAgICBudW1fbm9kZSA9IHNxcnQobGVuZ3RoKGZjX3ZlY3RvcikpCiAgICBtYXRyaXhfZmMgPSBtYXRyaXgoTkEsIG51bV9ub2RlLCBudW1fbm9kZSkKICAgIG1hdHJpeF9mYyA9IG1hdHJpeChmY192ZWN0b3IsIG51bV9ub2RlLCBudW1fbm9kZSkKICB9IGVsc2UgaWYgKG1ldGhvZCA9PSAiaGFsZiIpewogICAgbnVtX25vZGUgPSBjZWlsaW5nKHNxcnQobGVuZ3RoKGZjX3ZlY3RvcikqMikpCiAgICBtYXRyaXhfZmMgPSBtYXRyaXgoTkEsIG51bV9ub2RlLCBudW1fbm9kZSkKICAgIG1hdHJpeF9mY1tsb3dlci50cmkobWF0cml4X2ZjLCBkaWFnID0gRildID0gZmNfdmVjdG9yCiAgfSBlbHNlIGlmIChtZXRob2QgPT0gImhhbGYrZCIpIHsKICAgIG51bV9ub2RlID0gZmxvb3Ioc3FydChsZW5ndGgoZmNfdmVjdG9yKSoyKSkKICAgIG1hdHJpeF9mYyA9IG1hdHJpeChOQSwgbnVtX25vZGUsIG51bV9ub2RlKQogICAgbWF0cml4X2ZjW2xvd2VyLnRyaShtYXRyaXhfZmMsIGRpYWcgPSBUKV0gPSBmY192ZWN0b3IKICB9CiAgCiAgbWF0cml4X2ZjID0gc3ltbWV0cml6ZShtYXRyaXhfZmMsIHJ1bGUgPSAibG93ZXIiKQogIHJldHVybihtYXRyaXhfZmMpCn0KCmdldF9mY19jb20gPSBmdW5jdGlvbihhdGxhc19ub3csIHN1YmpfbmV0KSB7CiAgY29tX251bXMgPSByZWFkLnRhYmxlKGZpbGUucGF0aChhdGxhc19wYXRoLGF0bGFzX25vdyxwYXN0ZTAoYXRsYXNfbm93LCJDb21tdW5pdHlBZmZpbGlhdGlvbi4xRCIpKSkkVjEKICBjb21fbmFtZXMgPSByZWFkLnRhYmxlKGZpbGUucGF0aChhdGxhc19wYXRoLGF0bGFzX25vdyxwYXN0ZTAoYXRsYXNfbm93LCJDb21tdW5pdHlOYW1lcy50eHQiKSkpJFYxCiAgY29tX25hbWVzID0gc3Vic3RyKGNvbV9uYW1lcywwLDMpCiAgaWYgKGF0bGFzX25vdyA9PSAicG93ZXIyNjQiKSB7Y29tX25hbWVzW2MoMSwyKV0gPSBjKCJzbUgiLCJzbU0iKX0KICBmY19tYXRfbm93X2FsbCA9IGxpc3QoKQogIGNvbV9uYW1lX3ZlYyA9IGMoKQogIGZvciAobmV0XzEgaW4gMTptYXgoY29tX251bXMpKXsKICAgIG5vZGVfbm93XzEgPSB3aGljaChjb21fbnVtcyA9PSBuZXRfMSkKICAgIG5ldF9uYW1lXzEgPSBjb21fbmFtZXNbbmV0XzFdCiAgICBmb3IgKG5ldF8yIGluIDE6bWF4KGNvbV9udW1zKSl7CiAgICAgIG5vZGVfbm93XzIgPSB3aGljaChjb21fbnVtcyA9PSBuZXRfMikKICAgICAgbmV0X25hbWVfMiA9IGNvbV9uYW1lc1tuZXRfMl0KICAgICAgbmV0d29ya19ub3cgPSBwYXN0ZShuZXRfbmFtZV8xLG5ldF9uYW1lXzIsc2VwPSItIikKICAgICAgY29tX25hbWVfdmVjID0gYyhjb21fbmFtZV92ZWMsbmV0d29ya19ub3cpCiAgICAgIGZvciAoc3ViaiBpbiBzdWJqZWN0cykgewogICAgICBmY19tYXQgPSB2ZWN0b3JfdG9fbWF0KHN1YmpfbmV0W1thdGxhc19ub3ddXVtbc3Vial1dJFYxKQogICAgICBmY19tYXRfbm93ID0gZmNfbWF0W25vZGVfbm93XzEsbm9kZV9ub3dfMl0KICAgICAgZmNfbWF0X25vdyA9IGZjX21hdF9ub3dbbG93ZXIudHJpKGZjX21hdF9ub3cpXQogICAgICBmY19tYXRfbm93X2FsbFtbbmV0d29ya19ub3ddXVtbc3Vial1dJFYxID0gYXMudmVjdG9yKGZjX21hdF9ub3cpCiAgICAgIH0KICAgIH0KICB9CiAgY29tX25hbWVfbWF0ID0gdmVjdG9yX3RvX21hdChjb21fbmFtZV92ZWMsICJmdWxsIikKICBjb21fbmFtZV92ZWNfc2hvcnQgPSBjb21fbmFtZV9tYXRbbG93ZXIudHJpKGNvbV9uYW1lX21hdCwgZGlhZyA9IFQpXQogIGZjX21hdF9ub3dfYWxsX3Nob3J0ID0gZmNfbWF0X25vd19hbGxbbmFtZXMoZmNfbWF0X25vd19hbGwpICVpbiUgY29tX25hbWVfdmVjX3Nob3J0XSAgIAogIHJldHVybihmY19tYXRfbm93X2FsbF9zaG9ydCkKfQoKY29yX3Blcm0gPSBmdW5jdGlvbih4LCB5LCBwZXJtX3RpbWUsIG1ldGhvZCl7CiAgcmVhbF9jb3IgPSBzdXBwcmVzc1dhcm5pbmdzKGNvci50ZXN0KHgseSwgbWV0aG9kID0gbWV0aG9kKSkkZXN0aW1hdGUKICBwZXJtX2NvciA9IGMoKQogIGZvciAoaSBpbiAxOnBlcm1fdGltZSl7CiAgICB4ID0gc2FtcGxlKHgpCiAgICBwZXJtX2NvcltpXSA9IHN1cHByZXNzV2FybmluZ3MoY29yLnRlc3QoeCx5LCBtZXRob2QgPSBtZXRob2QpKSRlc3RpbWF0ZQogICAgaWYoaSA9PSAxMDAwKSB7cHJpbnQoaSl9CiAgfQogIGlmIChyZWFsX2NvciA+PTApewogICAgcF9wZXJtID0gbGVuZ3RoKHdoaWNoKHBlcm1fY29yID4gcmVhbF9jb3IpKS9wZXJtX3RpbWUKICB9IGVsc2UgewogICAgcF9wZXJtID0gbGVuZ3RoKHdoaWNoKHBlcm1fY29yIDwgcmVhbF9jb3IpKS9wZXJtX3RpbWUKICB9CiAgCiAgcmV0dXJuKHBfcGVybSkKfQoKCmZjX2NvbV9ncHMgPSBmdW5jdGlvbihzdWJqX25ldF9maWxlc18xLHN1YmpfbmV0X2ZpbGVzXzIsYXRsYXNfbm93KXsKICBhdGxhc19wYXRoID0gIi9Vc2Vycy9oeGlhL0RvY3VtZW50cy9HaXRIdWIveGNwRW5naW5lL2F0bGFzIgogIGZjX2NvbV8xID0gZ2V0X2ZjX2NvbShhdGxhc19ub3csIHN1YmpfbmV0ID0gc3Vial9uZXRfZmlsZXNfMSkKICBmY19jb21fMiA9IGdldF9mY19jb20oYXRsYXNfbm93LCBzdWJqX25ldCA9IHN1YmpfbmV0X2ZpbGVzXzIpCiAgZmNfY29tX2NvcnBsb3QgPSBzaW1fcGxvdHMoc3Vial9zZXEgPSBncHNfY29ycGxvdCRzdWJqLCBpZHMsbmFtZXMoZmNfY29tXzEpICwgZmNfY29tXzEsIGZjX2NvbV8yKQogIGZjX2NvbV9jb3JfciA9IGxhcHBseShmY19jb21fY29ycGxvdCwgZnVuY3Rpb24oYXRsYXMpIGF0bGFzJHNpbV9tYXQkcltsb3dlci50cmkoYXRsYXMkc2ltX21hdCRyKV0pCiAgZmNfY29tX2dwc19wdmFsdWUgPSB1bmxpc3Qoc2FwcGx5KGZjX2NvbV9jb3JfciwgZnVuY3Rpb24oYXRsYXMpIHN1cHByZXNzV2FybmluZ3MoY29yLnRlc3QoYXRsYXMsIGdwc19jb3JwbG90JHJbbG93ZXIudHJpKGdwc19jb3JwbG90JHIpXSwgbWV0aG9kID0gInNwZWFybWFuIikkcC52YWx1ZSkpKQogIGZjX2NvbV9ncHNfY29yID0gdW5saXN0KHNhcHBseShmY19jb21fY29yX3IsIGZ1bmN0aW9uKGF0bGFzKSBzdXBwcmVzc1dhcm5pbmdzKGNvci50ZXN0KGF0bGFzLCBncHNfY29ycGxvdCRyW2xvd2VyLnRyaShncHNfY29ycGxvdCRyKV0sIG1ldGhvZCA9ICJzcGVhcm1hbiIpJGVzdGltYXRlKSkpCiAgZmNfY29tX2dwc19wX3Blcm0gPSB1bmxpc3Qoc2FwcGx5KGZjX2NvbV9jb3JfciwgZnVuY3Rpb24oYXRsYXMpIGNvcl9wZXJtKGF0bGFzLCBncHNfY29ycGxvdCRyW2xvd2VyLnRyaShncHNfY29ycGxvdCRyKV0sMTAwMCwgIG1ldGhvZCA9ICJzcGVhcm1hbiIpKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAKICBmY19jb21fZ3BzX2Nvcl9kZiA9IGRhdGFfZnJhbWUoYXRsYXMgPSBnc3ViKCJcXC4uKiIsIiIsbmFtZXMoZmNfY29tX2dwc19jb3IpKSwgY29yciA9IGZjX2NvbV9ncHNfY29yLCBwX3ZhbCA9IGZjX2NvbV9ncHNfcHZhbHVlLCBwX3Blcm0gPSBmY19jb21fZ3BzX3BfcGVybSApCiAgZmNfY29tX2dwc19jb3JfZGYkcF92YWxfYWRqID0gcC5hZGp1c3QoZmNfY29tX2dwc19jb3JfZGYkcF92YWwsbWV0aG9kID0gImJvbmZlcnJvbmkiKQogIGZjX2NvbV9ncHNfY29yX2RmJHBfcGVybV9hZGogPSBwLmFkanVzdChmY19jb21fZ3BzX2Nvcl9kZiRwX3Blcm0sbWV0aG9kID0gImJvbmZlcnJvbmkiKQogIGZjX2NvbV9ncHNfY29yX2RmJHNpZyA9IGZjX2NvbV9ncHNfY29yX2RmJHBfdmFsX2FkajwgMC4wNQogIGZjX2NvbV9ncHNfY29yX2RmJHNpZ19wZXJtID0gZmNfY29tX2dwc19jb3JfZGYkcF9wZXJtX2FkajwgMC4wNQogIHAgPSBnZ3Bsb3QoZGF0YT1mY19jb21fZ3BzX2Nvcl9kZiwgYWVzKHg9cmVvcmRlcihhdGxhcywgLWNvcnIpLCB5PWNvcnIsIGZpbGwgPSBzaWdfcGVybSkpICsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMoLTAuNSwwLjUpKSArCiAgICB0aGVtZV9jb3dwbG90KCkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKwogICAgeWxhYigiRkMtR1BTIFNpbWlsYXJpdHkgTWF0cmljZXMgQ29ycmVsYXRvbnMiKSArIHhsYWIoIiIpICsgZ2d0aXRsZShhdGxhc19ub3cpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCiAgcmV0dXJuKGxpc3QoZmNfY29ycGxvdCA9IGZjX2NvbV9jb3JwbG90LCBmY19ncHNfZGYgPSBmY19jb21fZ3BzX2Nvcl9kZiwgcGxvdCA9IHAsIGNvbV9uYW1lcyA9IGNvbV9uYW1lcykpCn0KYGBgCgoKCmBgYHtyfQpmY19zY2hhZWYyMDBfN19jb21fZ3BzID0gZmNfY29tX2dwcyhzdWJqX25ldF9maWxlc18xLHN1YmpfbmV0X2ZpbGVzXzIsInNjaGFlZmVyMjAweDciKQpmY19wb3dlcl9jb21fZ3BzID0gZmNfY29tX2dwcyhzdWJqX25ldF9maWxlc18xLHN1YmpfbmV0X2ZpbGVzXzIsInBvd2VyMjY0IikKZmNfc2NoYWVmNDAwXzdfY29tX2dwcyA9IGZjX2NvbV9ncHMoc3Vial9uZXRfZmlsZXNfMSxzdWJqX25ldF9maWxlc18yLCJzY2hhZWZlcjQwMHg3IikKZmNfc2NoYWVmNDAwXzdfY29tX2dwcyRmY19jb3JwbG90JGB2aXMtZG9yYCRwbG90CmBgYAoKYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NX0KZmNfc2NoYWVmMjAwXzdfY29tX2dwcyRwbG90IC8gZmNfc2NoYWVmNDAwXzdfY29tX2dwcyRwbG90IC8gZmNfcG93ZXJfY29tX2dwcyRwbG90CmBgYAoKYGBge3IgbWFrZSB0aGluZ3MgdG8gbWF0LCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00fQpmY19jb21fZ3BzX291dF9jb3JwbG90ID0gZnVuY3Rpb24oZmNfY29tX2dwc19vdXQsIHRpdGxlKSB7CiAgdmVjdG9yX3RvX21hdChmY19jb21fZ3BzX291dCRmY19ncHNfZGYkYXRsYXMsImhhbGYrZCIpCiAgY29tX2dwc19jb3JyX21hdCA9IHZlY3Rvcl90b19tYXQoZmNfY29tX2dwc19vdXQkZmNfZ3BzX2RmJGNvcnIsImhhbGYrZCIpCiAgY29tX25hbWVzID0gZmNfY29tX2dwc19vdXQkY29tX25hbWVzCiAgcm93bmFtZXMoY29tX2dwc19jb3JyX21hdCkgPSBjb21fbmFtZXMKICBjb2xuYW1lcyhjb21fZ3BzX2NvcnJfbWF0KSA9IGNvbV9uYW1lcwogIGNvbV9ncHNfcHZhbF9tYXQgPSB2ZWN0b3JfdG9fbWF0KGZjX2NvbV9ncHNfb3V0JGZjX2dwc19kZiRwX3Blcm1fYWRqLCJoYWxmK2QiKQogIGNvbDIgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCIjNjcwMDFGIiwgIiNCMjE4MkIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI0ZGRkZGRiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjMjE2NkFDIiwgIiMwNTMwNjEiKSkKY29ycnBsb3QoY29tX2dwc19jb3JyX21hdCwgdHlwZT0iZnVsbCIsbWV0aG9kPSJjb2xvciIsIGNsLmxpbSA9IGMoLTAuMiwwLjIpLCB0bC5jb2w9ImJsYWNrIiwgCiAgICAgICAgICAgcC5tYXQgPSBjb21fZ3BzX3B2YWxfbWF0LCBzaWcubGV2ZWwgPSAwLjA1LCBpbnNpZyA9ICJibGFuayIsIAogICAgICAgICAgIGNvbCA9IHJldihjb2wyKDIwMCkpLCB0aXRsZSA9IHRpdGxlKQoKfQpgYGAKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQogZmNfY29tX2dwc19vdXRfY29ycGxvdChmY19zY2hhZWYyMDBfN19jb21fZ3BzLCAic2NoYWVmMjAwIikKCmBgYAoKYGBge3J9CmZjX2NvbV9ncHNfb3V0X2NvcnBsb3QoZmNfc2NoYWVmNDAwXzdfY29tX2dwcywgInNjaGFlZjQwMCIpIApgYGAKCmBgYHtyfQpmY19jb21fZ3BzX291dF9jb3JwbG90KGZjX3Bvd2VyX2NvbV9ncHMsICJwb3dlcjI2NCIpCmBgYAoKIyMjIDcuIE1hdGNoIEZDIHRhcmdldCB0byBkYXRhYmFzZQoKYGBge3J9CgpnZXRfYWNjX2ZpbmdlciA9IGZ1bmN0aW9uKHN1YmpfbmV0X2ZpbGVzXzEsc3Vial9uZXRfZmlsZXNfMil7CiAgY29yX2RmID0gbGlzdCgpCiAgYXRsYXNlcyA9IG5hbWVzKHN1YmpfbmV0X2ZpbGVzXzEpCiAgYWNjID0gYXJyYXkoKQogIGZvciAoYXRsYXMgaW4gYXRsYXNlcykgewogICAgY29yX21hdGNoID0gbGlzdCgpCiAgICBzdWJqX25ldF9maWxlc19hdGxhc18xID0gc3Vial9uZXRfZmlsZXNfMVtbYXRsYXNdXQogICAgc3Vial9uZXRfZmlsZXNfYXRsYXNfMiA9IHN1YmpfbmV0X2ZpbGVzXzJbW2F0bGFzXV0KICAgIGNvcl9tYXRjaFtbYXRsYXNdXSA9IGxhcHBseShzdWJqX25ldF9maWxlc19hdGxhc18xLCBmdW5jdGlvbihzdWJqX2Nvcl8xKSBzYXBwbHkoc3Vial9uZXRfZmlsZXNfYXRsYXNfMiwgZnVuY3Rpb24oc3Vial9jb3JfMikgY29yKHN1YmpfY29yXzEkVjEsIHN1YmpfY29yXzIkVjEsIHVzZSA9ICJuYS5vci5jb21wbGV0ZSIpKSkKICAgIGFjY1thdGxhc10gPSAwCiAgICBjb3JfbGlzdCA9IGxpc3QoKQogICAgZm9yKHN1YmogaW4gbmFtZXMoY29yX21hdGNoW1thdGxhc11dKSkgewogICAgICAgcG9zaXRpb24gPSB3aGljaC5tYXgodW5saXN0KGNvcl9tYXRjaFtbYXRsYXNdXVtbc3Vial1dKSkKICAgICAgIGNvcl9saXN0W1thdGxhc11dW1tzdWJqXV0gPSBtYXgodW5saXN0KGNvcl9tYXRjaFtbYXRsYXNdXVtbc3Vial1dKSkKICAgICAgIHByZWRpY3RlZF9zdWJqID0gc3ViamVjdHNbcG9zaXRpb25dCiAgICAgICBpZiAocHJlZGljdGVkX3N1YmogPT0gc3ViaikgewogICAgICAgICAgICBhY2NbYXRsYXNdPSBhY2NbYXRsYXNdICsgMQogICAgICAgICAgfQogICAgfQogICAgCiAgICBjb3JfZGZbW2F0bGFzXV0gPSBkYXRhLmZyYW1lKGJibGlkID0gYXMubnVtZXJpYyhuYW1lcyhjb3JfbGlzdFtbYXRsYXNdXSkpLCBmaW5nZXIgPSB1bmxpc3QoY29yX2xpc3RbW2F0bGFzXV0pKQogICAgYWNjW2F0bGFzXSA9IGFjY1thdGxhc10vbGVuZ3RoKGNvcl9tYXRjaFtbYXRsYXNdXSkKICB9CiAgICBhY2MgPSBhY2NbLTFdCiAgICByZXR1cm4obGlzdChjb3JfZGYgPSBjb3JfZGYsIGFjYyA9IGFjYykpCiAgfQoKc2luZ2xlX211bHRpX2FjYyA9IGdldF9hY2NfZmluZ2VyKHN1YmpfbmV0X2ZpbGVzXzEsc3Vial9uZXRfZmlsZXNfMikKc2luZ2xlX211bHRpX2FjY19kZiA9IGRhdGEuZnJhbWUoYXRsYXMgPSBuYW1lcyhzaW5nbGVfbXVsdGlfYWNjJGFjYyksIGFjY3VyYWN5ID0gc2luZ2xlX211bHRpX2FjYyRhY2MpCnAgPSBnZ3Bsb3QoZGF0YT1zaW5nbGVfbXVsdGlfYWNjX2RmLCBhZXMoeD1yZW9yZGVyKGF0bGFzLCBhY2N1cmFjeSksIHk9YWNjdXJhY3kpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArCiAgdGhlbWVfY293cGxvdCgpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAwLjUpKSArCiAgeWxhYigiRkMtR1BTIFNpbWlsYXJpdHkgTWF0cmljZXMgQ29ycmVsYXRvbnMiKSArIHhsYWIoIiIpCnAKCgpwc3ljaF9zdW1fZmluZ2VyID0gaW5uZXJfam9pbihjb3JfZGYscHN5Y2hfc3VtLCBieSA9IGMoJ2JibGlkJyA9ICdCQkxJRCcpKQoKZml0ID0gbG0oIGFjYyB+IGZpbmdlciArICBzdW1fYWxzICsgZGF5cywgZGF0YSA9IHBzeWNoX3N1bV9maW5nZXIpCnN1bW1hcnkoZml0KQpgYGAKCgojIyMgOC4gUGVybXV0YXRpb24gVGVzdCBmb3IgTWF0Y2hpbmcKYGBge3J9CmdldF9zdWJqX25ldF9wZXJtID0gZnVuY3Rpb24oc3Vial9uZXRfZmlsZXMpewogIHN1YmpfbmV0X3Blcm0gPSBsaXN0KCkKICBhdGxhc2VzID0gbmFtZXMoc3Vial9uZXRfZmlsZXMpCiAgZm9yIChhdGxhcyBpbiBhdGxhc2VzKXsKICAgIHJhbmRvbV9zZXEgPSBzYW1wbGUobGVuZ3RoKHN1YmpfbmV0X2ZpbGVzW1thdGxhc11dKSkKICAgIHN1YmpfbmV0X3Blcm1bW2F0bGFzXV0gPSBzdWJqX25ldF9maWxlc1tbYXRsYXNdXVtyYW5kb21fc2VxXQogICAgbmFtZXMoc3Vial9uZXRfcGVybVtbYXRsYXNdXSkgPSBuYW1lcyhzdWJqX25ldF9maWxlc1tbYXRsYXNdXSkKICB9CiAgcmV0dXJuKHN1YmpfbmV0X3Blcm0pCn0KCnN1YmpfbmV0X3Blcm1fMSA9IGdldF9zdWJqX25ldF9wZXJtKHN1YmpfbmV0X2ZpbGVzXzEpCnN1YmpfbmV0X3Blcm1fMiA9IGdldF9zdWJqX25ldF9wZXJtKHN1YmpfbmV0X2ZpbGVzXzIpCgpgYGAKCmBgYHtyfQpwZXJtX3RpbWUgPSAxMDAwCnNpbmdsZV9tdWx0aV9hY2NfcGVybSA9IGxpc3QoKQpmb3IgKGkgaW4gMTpwZXJtX3RpbWUpewogIHByaW50KGkpCiAgc3Vial9uZXRfcGVybV8xID0gZ2V0X3N1YmpfbmV0X3Blcm0oc3Vial9uZXRfZmlsZXNfMSkKICBzdWJqX25ldF9wZXJtXzIgPSBnZXRfc3Vial9uZXRfcGVybShzdWJqX25ldF9maWxlc18yKQogIHNpbmdsZV9tdWx0aV9hY2NfcGVybVtbaV1dID0gZ2V0X2FjY19maW5nZXIoc3Vial9uZXRfcGVybV8xLHN1YmpfbmV0X3Blcm1fMikKICBwcmludChzaW5nbGVfbXVsdGlfYWNjX3Blcm1bW2ldXSRhY2MpCn0KCmBgYAoKYGBge3J9CnBlcm1fYWNjID0gYXMuZGF0YS5mcmFtZSh0KHNhcHBseShzaW5nbGVfbXVsdGlfYWNjX3Blcm0sIGZ1bmN0aW9uKHBlcm0pIHBlcm0kYWNjKSkpCnBlcm1fYWNjX2xvbmcgPC0gZ2F0aGVyKHBlcm1fYWNjLCBrZXkgPSAiYXRsYXMiLCB2YWx1ZSA9ICJhY2N1cmFjeSIsIGFsbF9vZihhdGxhc2VzKSwgZmFjdG9yX2tleT1UUlVFKQpwPC1nZ3Bsb3QocGVybV9hY2NfbG9uZywgYWVzKHg9YXRsYXMsIHk9YWNjdXJhY3ksIGZpbGwgPSBhdGxhcykpICsgCiAgIGdlb21faml0dGVyKHNob3cubGVnZW5kID0gRikgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMoLTAuMSwwLjUpKSArCiAgIGdndGl0bGUoIlBlcm11dGF0aW9uIFRlc3QgZm9yIEZDIEZpbmdlcnByaW50aW5nIikgKyB0aGVtZV9jb3dwbG90KCkgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDAuNSkpCnAKYGBgCgpgYGB7ciB1c2Ugb25seSB0aGUgR1BTLUZDIHNpZ25pZmljYW50IG5ldHdvcmtzIHRvIHByZWRpY3QgaW5kaXZpZHVhbHN9CmdldF9jb21fZmNfYWNjdXJhY3kgPSBmdW5jdGlvbihhdGxhc19ub3cpewogIGZjX2NvbV8xICA9IGdldF9mY19jb20oYXRsYXNfbm93LCBzdWJqX25ldF9maWxlc18xKQogIGZjX2NvbV8yICA9IGdldF9mY19jb20oYXRsYXNfbm93LCBzdWJqX25ldF9maWxlc18yKQogICNmY19jb21fMV9zaWcgPSBmY19jb21fMVtuYW1lcyh3aGljaChmY19zY2hhZWY0MDBfN19jb21fZ3BzJGZjX2dwc19kZiRzaWcgPT0gVCkpXQogICNmY19jb21fMl9zaWcgPSBmY19jb21fMltuYW1lcyh3aGljaChmY19zY2hhZWY0MDBfN19jb21fZ3BzJGZjX2dwc19kZiRzaWcgPT0gVCkpXQogIHNpbmdsZV9tdWx0aV9hY2NfY29tID0gZ2V0X2FjY19maW5nZXIoZmNfY29tXzEsZmNfY29tXzIpCiAgc2luZ2xlX211bHRpX2FjY19jb21fZGYgPSBkYXRhLmZyYW1lKGF0bGFzID0gbmFtZXMoc2luZ2xlX211bHRpX2FjY19jb20kYWNjKSwgYWNjdXJhY3kgPSBzaW5nbGVfbXVsdGlfYWNjX2NvbSRhY2MsIEZDX0dQU19zaWcgPSBmY19zY2hhZWY0MDBfN19jb21fZ3BzJGZjX2dwc19kZiRzaWcgPT0gVCkKICBwID0gZ2dwbG90KGRhdGE9c2luZ2xlX211bHRpX2FjY19jb21fZGYsIGFlcyh4PXJlb3JkZXIoYXRsYXMsIGFjY3VyYWN5KSwgeT1hY2N1cmFjeSwgZmlsbCA9IEZDX0dQU19zaWcpKSArCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICAgIHRoZW1lX2Nvd3Bsb3QoKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41KSkgKwogICAgeWxhYigiRkMgRmluZ2VycHJpbnQgQWNjdXJhY3kiKSArIHhsYWIoIiIpCgpyZXR1cm4obGlzdChkZiA9IHNpbmdsZV9tdWx0aV9hY2NfY29tX2RmLCBwbG90ID0gcCkpCn0KczQwMF9mY19jb21fYWNjID0gZ2V0X2NvbV9mY19hY2N1cmFjeSgic2NoYWVmZXI0MDB4NyIpCnMyMDBfZmNfY29tX2FjYyA9IGdldF9jb21fZmNfYWNjdXJhY3koInNjaGFlZmVyMjAweDciKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTR9CgpzNDAwX2ZjX2NvbV9hY2MkcGxvdCAvIHMyMDBfZmNfY29tX2FjYyRwbG90CmBgYAoKCmBgYHtyIGlycml0YWJpbGl0eSBhbmQgc3BlY2lmaWMgbmV0d29ya3N9CnM0MDBfZmNfY29tX2FjY19zdWJzZXQgPSBzdWJzZXQoczQwMF9mY19jb21fYWNjJGRmLCBGQ19HUFNfc2lnID09IFQpCnM0MDBfZmNfY29tXzEgID0gZ2V0X2ZjX2NvbSgic2NoYWVmZXI0MDB4NyIsIHN1YmpfbmV0X2ZpbGVzXzEpCnM0MDBfZmNfY29tXzIgID0gZ2V0X2ZjX2NvbSgic2NoYWVmZXI0MDB4NyIsIHN1YmpfbmV0X2ZpbGVzXzIpCm1vdGlvbl9maWxlc18xID0gbGlzdCgpCm1vdGlvbl9maWxlc18yID0gbGlzdCgpCmF0bGFzX25vdyA9ICJzY2hhZWZlcjQwMHg3IgpzdWJqZWN0cyA9IGxpc3QuZmlsZXMoZmlsZS5wYXRoKGRhdGFfcGF0aCwiLi4vIiwicXVhbGl0eV9jc3YiKSkKZm9yIChzdWJqIGluIHN1YmplY3RzKSB7CiAgc3Vial9maWxlcyA9IGxpc3QuZmlsZXMoZmlsZS5wYXRoKGRhdGFfcGF0aCwiLi4vIiwicXVhbGl0eV9jc3YiLCBzdWJqKSkKICBtb3Rpb25fMSA9IHBhc3RlMCgiKnRhc2stcmVzdCpzaW5nbGUqIikKICBtb3Rpb25fMiA9IHBhc3RlMCgiKnRhc2stcmVzdCptdWx0aSoiKQogIAogIGZpbGVfcGF0aF8xID0gZmlsZS5wYXRoKGRhdGFfcGF0aCwgIi4uLyIsInF1YWxpdHlfY3N2IiwKICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJqLHN1YmpfZmlsZXNbZ3JlcChnbG9iMnJ4KG1vdGlvbl8xKSxzdWJqX2ZpbGVzKV0pCiAgZmlsZV9wYXRoXzIgPSBmaWxlLnBhdGgoZGF0YV9wYXRoLCAiLi4vIiwicXVhbGl0eV9jc3YiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHN1Ymosc3Vial9maWxlc1tncmVwKGdsb2IycngobW90aW9uXzIpLHN1YmpfZmlsZXMpXSkKICBpZiAobGVuZ3RoKGZpbGVfcGF0aF8xKT4wKSB7bW90aW9uX2ZpbGVzXzFbW3N1YmpdXSA9IHJlYWQudGFibGUoZmlsZV9wYXRoXzEpIH0KICBpZiAobGVuZ3RoKGZpbGVfcGF0aF8yKT4wKSB7bW90aW9uX2ZpbGVzXzJbW3N1YmpdXSA9IHJlYWQudGFibGUoZmlsZV9wYXRoXzIpIH0KfQoKCmdldF9uZXRfc3Vial9kZiA9IGZ1bmN0aW9uKG5ldCkgewogIG5ldF9zdWJqID0gc2FwcGx5KG5ldCwgZnVuY3Rpb24oc3ViaikgbWVhbihzdWJqJFYxKSkKICBuZXRfc3Vial9kZiA9IGRhdGEuZnJhbWUoc3ViaiA9IGFzLm51bWVyaWMobmFtZXMobmV0X3N1YmopKSwgbWVhbiA9IG5ldF9zdWJqKQogIHJldHVybihuZXRfc3Vial9kZikKfQoKczQwMF9mY19jb21fbWVhbl8xID0gbGFwcGx5KHM0MDBfZmNfY29tXzFbczQwMF9mY19jb21fYWNjX3N1YnNldCRhdGxhc10sIGZ1bmN0aW9uKG5ldCkgZ2V0X25ldF9zdWJqX2RmKG5ldCkpCnM0MDBfZmNfY29tX21lYW5fMiA9IGxhcHBseShzNDAwX2ZjX2NvbV8yW3M0MDBfZmNfY29tX2FjY19zdWJzZXQkYXRsYXNdLCBmdW5jdGlvbihuZXQpIGdldF9uZXRfc3Vial9kZihuZXQpKQoKczQwMF9mY19jb21fbWVhbl8xX2dwcyA9IGxhcHBseShzNDAwX2ZjX2NvbV9tZWFuXzEsIGZ1bmN0aW9uKG5ldCkgaW5uZXJfam9pbihwc3ljaF9zdW0sIG5ldCwgYnkgPSBjKCJCQkxJRCIgPSAic3ViaiIpKSkKCiAgI2ZjX2NvbV8xX3NpZyA9IGZjX2NvbV8xW25hbWVzKHdoaWNoKGZjX3NjaGFlZjQwMF83X2NvbV8gZ3BzJGZjX2dwc19kZiRzaWcgPT0gVCkpXQogICNmY19jb21fMl9zaWcgPSBmY19jb21fMltuYW1lcyh3aGljaChmY19zY2hhZWY0MDBfN19jb21fZ3BzJGZjX2dwc19kZiRzaWcgPT0gVCkpXQogIHNpbmdsZV9tdWx0aV9hY2NfY29tID0gZ2V0X2FjY19maW5nZXIoZmNfY29tXzEsZmNfY29tXzIpCiAgc2luZ2xlX211bHRpX2FjY19jb21fZGYgPSBkYXRhLmZyYW1lKGF0bGFzID0gbmFtZXMoc2luZ2xlX211bHRpX2FjY19jb20kYWNjKSwgYWNjdXJhY3kgPSBzaW5nbGVfbXVsdGlfYWNjX2NvbSRhY2MsIEZDX0dQU19zaWcgPSAKYGBgCgo=
A work by Cedric Huchuan Xia
hxia@upenn.edu